<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/5/12 0012
 * Time: 10:16
 */

namespace App\Socket\Services;


use App\Socket\Models\Protocol;
use App\Socket\Packets\DispatchPacket;
use Predis\Client;

class SocketServerEvent
{
    /**
     * @var SocketServerEvent
     */
    private static $instance;

    /**
     * 半包、粘包情况下记录的数据
     * @var array
     */
    private static $buffer;

    /**
     * @return SocketServerEvent
     */
    public static function instance()
    {
        if (self::$instance == null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 接收到客户端消息
     * @param \swoole_websocket_server $server
     * @param $frame
     */
    public function onMessage(\swoole_websocket_server $server, $frame)
    {
        //数据帧不完整的情况下，缓存数据 -- 解决半包的情况
        if (empty($frame->finish)) {
            if (empty(self::$buffer[$frame->fd])) {
                self::$buffer[$frame->fd] = $frame->data;
            } else {
                self::$buffer[$frame->fd] .= $frame->data;
            }
            return;
        }
        if (!empty(self::$buffer[$frame->fd])) {
            $frame->data = self::$buffer[$frame->fd] . $frame->data;
            unset(self::$buffer[$frame->fd]);
        }
        //接收到的包 放到task进程处理
        $server->task(json_encode($frame));
    }

    /**
     * 客户端断开连接
     * @param \swoole_server $server
     * @param int $fd
     * @param int $reactorId
     */
    public function onClose(\swoole_server $server, int $fd, int $reactorId)
    {
        echo "client {$fd} closed\n";
    }

    /**
     * worker/task进程启动
     * @param \swoole_server $server
     * @param $workerId
     */
    public function onWorkStart(\swoole_server $server, $workerId)
    {
        if($workerId == 0) {
            \swoole_timer_tick(100, function () use ($server) {
                $redis = new Client(config('database.redis.default'));
                $data = $redis->lpop(config('socket.websocket.channel'));
                if(!empty($data)){
                    echo 'redis get channel data:'.$data.PHP_EOL;
                    $data = json_decode($data,true);
                    foreach ($server->connections as $fd){
                        SocketServer::instance()->push($fd,Protocol::toObject($data));
                    }
                }
            });
        }
    }

    /**
     * task进程 处理耗时任务
     * @param \swoole_server $server
     * @param int $taskId
     * @param int $workerId
     * @param string $data
     * @return string
     */
    public function onTask(\swoole_server $server, int $taskId, int $workerId, string $data)
    {
        try {
            $frame = json_decode($data, true);
            $protocol = Protocol::toObject(@json_decode($frame['data'], true));
            $result = DispatchPacket::handle($protocol,$frame['fd']);
            if(!is_null($result)){
                SocketServer::instance()->push($frame['fd'],$result);
            }
            unset($frame,$data);
        }catch (\Exception $e){
            echo $e->getMessage().PHP_EOL;
        }
    }

    /**
     * task进程 任务处理完成
     * @param \swoole_server $server
     * @param int $taskId
     * @param string $data
     */
    public function onFinish(\swoole_server $server, int $taskId, string $data)
    {

    }

    /**
     * http服务
     * @param \swoole_http_request $request
     * @param \swoole_http_response $response
     */
    public function onRequest(\swoole_http_request $request, \swoole_http_response $response)
    {
        $response->status(404);
    }
}